{-
 Copyright 2022-23, Juspay India Pvt Ltd

 This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License

 as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program

 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY

 or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. You should have received a copy of

 the GNU Affero General Public License along with this program. If not, see <https://www.gnu.org/licenses/>.
-}

module SharedLogic.CallBAPInternal where

import API.Types.UI.MeterRide
import qualified API.Types.UI.PickupInstructions as PickupInstructions
import qualified Data.HashMap.Strict as HM
import qualified Data.Text
import Domain.Types.Ride as DRide
import EulerHS.Types (EulerClient, client)
import Kernel.External.Slack.Types
import Kernel.Prelude
import Kernel.Types.APISuccess
import Kernel.Types.Id (Id)
import Kernel.Utils.Common hiding (Error)
import Kernel.Utils.Dhall (FromDhall)
import qualified Kernel.Utils.Servant.Client as EC
import Servant hiding (throwError)
import Tools.Metrics (CoreMetrics)

data FeedbackReq = FeedbackReq
  { rideId :: Id DRide.Ride,
    ratingValue :: Int,
    feedbackDetails :: Maybe Text
  }
  deriving (Generic, ToJSON, FromJSON, ToSchema)

data AppBackendBapInternal = AppBackendBapInternal
  { name :: Text,
    url :: BaseUrl,
    apiKey :: Text,
    internalKey :: Text
  }
  deriving (Generic, FromDhall)

type FeedBackAPI =
  "internal"
    :> "feedback"
    :> "rateRide"
    :> Header "token" Text
    :> ReqBody '[JSON] FeedbackReq
    :> Post '[JSON] APISuccess

feedbackClient :: Maybe Text -> FeedbackReq -> EulerClient APISuccess
feedbackClient = client (Proxy @FeedBackAPI)

feedbackApi :: Proxy FeedBackAPI
feedbackApi = Proxy

feedback ::
  ( MonadFlow m,
    CoreMetrics m,
    HasFlowEnv m r '["internalEndPointHashMap" ::: HM.HashMap BaseUrl BaseUrl],
    HasRequestId r
  ) =>
  Text ->
  BaseUrl ->
  FeedbackReq ->
  m APISuccess
feedback apiKey internalUrl request = do
  internalEndPointHashMap <- asks (.internalEndPointHashMap)
  EC.callApiUnwrappingApiError (identity @Error) Nothing (Just "BAP_INTERNAL_API_ERROR") (Just internalEndPointHashMap) internalUrl (feedbackClient (Just apiKey) request) "FeedBack" feedbackApi

type StopEventsAPI =
  "internal"
    :> "stopEvents"
    :> "stop"
    :> Header "token" Text
    :> ReqBody '[JSON] StopEventsReq
    :> Post '[JSON] APISuccess

data StopEventsReq = StopEventsReq
  { action :: StopAction,
    rideId :: Id DRide.Ride,
    stopOrder :: Int,
    waitingTimeStart :: UTCTime,
    waitingTimeEnd :: Maybe UTCTime
    -- stopId :: Id DRide.Stop
  }
  deriving (Generic, ToJSON, FromJSON, ToSchema)

data StopAction = Depart | Arrive
  deriving (Generic, ToJSON, FromJSON, ToSchema)

stopEventsClient :: Maybe Text -> StopEventsReq -> EulerClient APISuccess
stopEventsClient = client (Proxy @StopEventsAPI)

stopEventsApi :: Proxy StopEventsAPI
stopEventsApi = Proxy

stopEvents ::
  ( MonadFlow m,
    CoreMetrics m,
    HasFlowEnv m r '["internalEndPointHashMap" ::: HM.HashMap BaseUrl BaseUrl],
    HasRequestId r
  ) =>
  Text ->
  BaseUrl ->
  StopEventsReq ->
  m APISuccess
stopEvents apiKey internalUrl request = do
  internalEndPointHashMap <- asks (.internalEndPointHashMap)
  EC.callApiUnwrappingApiError (identity @Error) Nothing (Just "BAP_INTERNAL_API_ERROR") (Just internalEndPointHashMap) internalUrl (stopEventsClient (Just apiKey) request) "StopEvents" stopEventsApi

-- manually added this for BAP internal API generated by DSL in rider side. (request types is same so didn't had to create one here)
type MeterRideAddDestinationAPI =
  "internal"
    :> Capture "bppRideId" Text
    :> "addDestination"
    :> Header "token" Text
    :> ReqBody '[JSON] MeterRideAddDestinationReq
    :> Post '[JSON] APISuccess

meterRideAddDestinationClient :: Text -> Maybe Text -> MeterRideAddDestinationReq -> EulerClient APISuccess
meterRideAddDestinationClient = client (Proxy @MeterRideAddDestinationAPI)

meterRideAddDestinationAPI :: Proxy MeterRideAddDestinationAPI
meterRideAddDestinationAPI = Proxy

meterRideAddDestination ::
  ( MonadFlow m,
    CoreMetrics m,
    HasFlowEnv m r '["internalEndPointHashMap" ::: HM.HashMap BaseUrl BaseUrl],
    HasRequestId r
  ) =>
  Text ->
  BaseUrl ->
  Text ->
  MeterRideAddDestinationReq ->
  m APISuccess
meterRideAddDestination apiKey internalUrl rideId request = do
  internalEndPointHashMap <- asks (.internalEndPointHashMap)
  EC.callApiUnwrappingApiError (identity @Error) Nothing (Just "BAP_INTERNAL_API_ERROR") (Just internalEndPointHashMap) internalUrl (meterRideAddDestinationClient rideId (Just apiKey) request) "StopEvents" meterRideAddDestinationAPI

type GetCustomerReferralInfoAPI =
  "internal"
    :> "getCustomerInfo"
    :> Header "token" Data.Text.Text
    :> ReqBody '[JSON] SendRecietRequest
    :> Get '[JSON] CustomerInfoResponse

data CustomerInfoResponse = CustomerInfoResponse
  { alreadyReferred :: Maybe Bool,
    isMultipleDeviceIdExist :: Maybe Bool
  }
  deriving (Generic, ToJSON, FromJSON)

getCustomerReferralInfoClient :: Maybe Text -> SendRecietRequest -> EulerClient CustomerInfoResponse
getCustomerReferralInfoClient = client (Proxy @GetCustomerReferralInfoAPI)

getCustomerReferralInfoAPI :: Proxy GetCustomerReferralInfoAPI
getCustomerReferralInfoAPI = Proxy

getCustomerReferralInfo ::
  ( MonadFlow m,
    CoreMetrics m,
    HasFlowEnv m r '["internalEndPointHashMap" ::: HM.HashMap BaseUrl BaseUrl],
    HasRequestId r
  ) =>
  Text ->
  BaseUrl ->
  SendRecietRequest ->
  m CustomerInfoResponse
getCustomerReferralInfo apiKey internalUrl request = do
  internalEndPointHashMap <- asks (.internalEndPointHashMap)
  EC.callApiUnwrappingApiError (identity @Error) Nothing (Just "BAP_INTERNAL_API_ERROR") (Just internalEndPointHashMap) internalUrl (getCustomerReferralInfoClient (Just apiKey) request) "StopEvents" getCustomerReferralInfoAPI

type GetInsuranceInfoAPI =
  "internal"
    :> "insurance"
    :> Capture "rideId" Text
    :> Header "token" Text
    :> Get '[JSON] InsuranceAPIEntity

data InsuranceAPIEntity = InsuranceAPIEntity
  { certificateUrl :: Maybe Text,
    plan :: Maybe Text,
    policyId :: Maybe Text,
    policyNumber :: Maybe Text,
    message :: Text
  }
  deriving (Generic, ToJSON, FromJSON, ToSchema)

getInsuranceInfo ::
  ( MonadFlow m,
    CoreMetrics m,
    HasFlowEnv m r '["internalEndPointHashMap" ::: HM.HashMap BaseUrl BaseUrl],
    HasRequestId r
  ) =>
  Text ->
  BaseUrl ->
  Text ->
  m InsuranceAPIEntity
getInsuranceInfo apiKey internalUrl rideId = do
  internalEndPointHashMap <- asks (.internalEndPointHashMap)
  EC.callApiUnwrappingApiError (identity @Error) Nothing (Just "BAP_INTERNAL_API_ERROR") (Just internalEndPointHashMap) internalUrl (getInsuranceInfoClient rideId (Just apiKey)) "GetInsuranceInfo" getInsuranceInfoAPI

getInsuranceInfoClient :: Text -> Maybe Text -> EulerClient InsuranceAPIEntity
getInsuranceInfoClient = client (Proxy @GetInsuranceInfoAPI)

getInsuranceInfoAPI :: Proxy GetInsuranceInfoAPI
getInsuranceInfoAPI = Proxy

type RideSearchExpiredAPI =
  "internal"
    :> "rideSearchExpired"
    :> Header "token" Text
    :> ReqBody '[JSON] RideSearchExpiredReq
    :> Post '[JSON] APISuccess

newtype RideSearchExpiredReq = RideSearchExpiredReq
  {transactionId :: Text}
  deriving (Generic, ToJSON, FromJSON)

rideSearchExpiredClient :: Maybe Text -> RideSearchExpiredReq -> EulerClient APISuccess
rideSearchExpiredClient = client (Proxy @RideSearchExpiredAPI)

rideSearchExpiredAPI :: Proxy RideSearchExpiredAPI
rideSearchExpiredAPI = Proxy

rideSearchExpired ::
  ( MonadFlow m,
    CoreMetrics m,
    HasFlowEnv m r '["internalEndPointHashMap" ::: HM.HashMap BaseUrl BaseUrl],
    HasRequestId r
  ) =>
  Text ->
  BaseUrl ->
  RideSearchExpiredReq ->
  m APISuccess
rideSearchExpired apiKey internalUrl request = do
  logInfo "BPP handle rideSearchExpired callBAPInternal"
  internalEndPointHashMap <- asks (.internalEndPointHashMap)
  EC.callApiUnwrappingApiError (identity @Error) Nothing (Just "BAP_INTERNAL_API_ERROR") (Just internalEndPointHashMap) internalUrl (rideSearchExpiredClient (Just apiKey) request) "rideSearchExpired" rideSearchExpiredAPI

type GetPickupInstructionsAPI =
  "internal"
    :> Capture "rideId" Text
    :> "pickupInstructions"
    :> Header "token" Text
    :> Get '[JSON] PickupInstructions.PickupInstructionResp

getPickupInstructionsClient :: Text -> Maybe Text -> EulerClient PickupInstructions.PickupInstructionResp
getPickupInstructionsClient = client (Proxy @GetPickupInstructionsAPI)

getPickupInstructionsAPI :: Proxy GetPickupInstructionsAPI
getPickupInstructionsAPI = Proxy

getPickupInstructions ::
  ( MonadFlow m,
    CoreMetrics m,
    HasFlowEnv m r '["internalEndPointHashMap" ::: HM.HashMap BaseUrl BaseUrl],
    HasRequestId r
  ) =>
  Text ->
  BaseUrl ->
  Text ->
  m PickupInstructions.PickupInstructionResp
getPickupInstructions apiKey internalUrl rideId = do
  logInfo $ "CallBAPInternal: Calling BAP internal API for pickup instructions, rideId: " <> rideId
  internalEndPointHashMap <- asks (.internalEndPointHashMap)
  EC.callApiUnwrappingApiError (identity @Error) Nothing (Just "BAP_INTERNAL_API_ERROR") (Just internalEndPointHashMap) internalUrl (getPickupInstructionsClient rideId (Just apiKey)) "GetPickupInstructions" getPickupInstructionsAPI
